package main

import (
	"bufio"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/axgle/mahonia"
	"io"
	"log"
	"math/rand"
	"net/http"
	"os"
	"strings"
)

//http://search.dangdang.com/?key=java&act=input&show=big#J_tab
func main() {
	if len(os.Args) <= 1 {
		log.Fatalln("参数异常，没有找到URL配置文件！")
	}
	sqlFile, err := os.Create("bookinfo.sql")
	if err != nil {
		log.Fatalln(err)
	}
	readURL(os.Args[1], func(url string, kindID int) {
		downHTML(url, "tmp.html")
		analysisSearch("tmp.html", sqlFile, kindID)
	})
	sqlFile.Close()
}

func readURL(fileName string, urlHandc func(string, int)) {
	file, err := os.OpenFile(fileName, os.O_RDWR, 0666)
	if err != nil {
		log.Fatalln("Open file error!", err)
	}
	defer file.Close()

	stat, err := file.Stat()
	if err != nil {
		log.Fatalln("Open file error!", err)
	}

	var size = stat.Size()
	log.Println("file size=", size)

	buf := bufio.NewReader(file)
	kindID := 1
	for {
		line, err := buf.ReadString('\n')
		line = strings.TrimSpace(line)
		log.Println("url", line)
		urlHandc(line, kindID)
		kindID++
		if err != nil {
			if err == io.EOF {
				log.Println("File read ok!")
				break
			} else {
				log.Fatalln("Read file error!", err)
				return
			}
		}
	}
}

// BookInfo 实体类
type BookInfo struct {
	Name              string
	Author            string
	AuthorNationality string
	Publisher         string
	PublicationTime   string
	Price             string
	Summary           string
	KindID            int
	Picture           string
	Remaining         uint
}

func analysisSearch(filePath string, sqlFile *os.File, kindID int) {
	file, err := os.Open(filePath)
	if err != nil {
		log.Fatalln("analysisSearch Err", filePath)
		return
	}
	doc, err := goquery.NewDocumentFromReader(file)
	if err != nil {
		log.Fatalln("analysisSearch Err", filePath)
		return
	}
	ul := doc.Find("ul.cloth_shoplist")
	createSQLCount := 0
	ul.Children().EachWithBreak(func(i int, selection *goquery.Selection) bool {
		a := selection.Find("a.pic")
		href, ok := a.Attr("href")
		if ok {
			book := BookInfo{}
			book.KindID = kindID
			price := []rune(selection.Find("p.price").Find("span.price_n").Text())
			book.Price = string(price[1:])
			downHTML(href, "tmp2.html")
			log.Println("下载完毕!", createSQLCount, href)
			analysisDetail(&book, "tmp2.html")
			count := rand.Intn(3) * rand.Intn(33)
			sql := createSQL(&book, count)
			n, err := sqlFile.WriteString(sql)
			log.Println("Write SQL", n, err)
			createSQLCount++
			if createSQLCount > 30 {
				return false
			}
		} else {
			str, err := a.Html()
			log.Println("Not found href!", str, err)
		}
		return true
	})
}

func analysisDetail(book *BookInfo, filePath string) {
	file, err := os.Open(filePath)
	if err != nil {
		log.Println("analysisDetail Err", filePath)
		return
	}
	doc, err := goquery.NewDocumentFromReader(file)
	if err != nil {
		log.Println("analysisDetail Err", filePath)
		return
	}
	book.Picture, _ = doc.Find("#largePic").Attr("src")

	bookInfo := doc.Find("#product_info")
	nameInfo := bookInfo.Find("div.name_info")
	//
	book.Name, _ = nameInfo.Find("h1").Attr("title")
	//
	book.Summary, _ = nameInfo.Find("h2").Find("span.hot").Attr("title")
	//
	author := doc.Find("#author")
	book.Author = author.Find("a").Text()
	//
	publisher := author.Next()
	book.Publisher = publisher.Find("a").Text()
	//
	year := rand.Intn(14) + 2004
	month := rand.Intn(12) + 1
	day := rand.Intn(26) + 1
	book.PublicationTime = fmt.Sprintf("%d-%d-%d", year, month, day)
}

func showOne(i int, selection *goquery.Selection) {
	log.Println(selection.First().Html())
}

func downHTML(url string, fileSave string) {
	res, err := http.Get(url)
	if err != nil {
		log.Fatalln(err)
	}
	file, err := os.Create(fileSave)
	if err != nil {
		log.Fatalln(err)
	}
	buf := make([]byte, 2048)
	for {
		if n, err := res.Body.Read(buf); n > 0 {
			if err != nil {
				log.Println(err)
				return
			}
			res := convert(buf[0:n], "gbk", "utf-8")

			_, err := file.Write(res)
			if err != nil {
				log.Println(err)
				return
			}
		} else {
			log.Println("over!")
		}
	}
}

func convert(buf []byte, srcCode string, tagCode string) []byte {
	srcCoder := mahonia.NewDecoder(srcCode)
	srcResult := srcCoder.ConvertString(string(buf))
	tagCoder := mahonia.NewDecoder(tagCode)
	_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
	return cdata
}

func convertGBK2utf8(buf []byte) []byte {
	return convert(buf, "gbk", "utf8")
}

func convertToString(buf string, srcCode string, tagCode string) string {
	srcCoder := mahonia.NewDecoder(srcCode)
	srcResult := srcCoder.ConvertString(buf)
	tagCoder := mahonia.NewDecoder(tagCode)
	_, cdata, _ := tagCoder.Translate([]byte(srcResult), true)
	return string(cdata)
}

func convertGBK2utf8String(buf string) string {
	return convertToString(strings.Trim(buf, " "), "gbk", "utf8")
}

func createSQL(book *BookInfo, remaining int) string {
	sql := `INSERT INTO t_book_info 
	(name,author,author_nationality,publisher,publication_time,price,summary,kind_id,picture,remaining,create_time) 
		VALUES 
	('%s', '%s', %s, '%s', '%s', %s, '%s', %d, '%s', %d,'%s');`
	return fmt.Sprintf(sql, book.Name, book.Author, "NULL", book.Publisher, book.PublicationTime, book.Price, book.Summary, book.KindID, book.Picture, remaining, "2017-02-03")
}
